﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;
using System.Windows;
using System.Windows.Media;
using System.Windows.Data;

namespace Eniux.Windows.ThreeDEngine.Visual3Ds
{
    /// <summary>
    /// 组合操纵器（平移和旋转）
    /// </summary>
    public class CombinedManipulator : ModelVisual3D
    {

        #region 变量

        /// <summary>
        /// X轴旋转操纵器
        /// </summary>
        private readonly RotateManipulator RotateXManipulator;

        /// <summary>
        /// Y轴旋转操纵器
        /// </summary>
        private readonly RotateManipulator RotateYManipulator;

        /// <summary>
        /// Z轴旋转操纵器
        /// </summary>
        private readonly RotateManipulator RotateZManipulator;

        /// <summary>
        ///X轴平移操纵器
        /// </summary>
        private readonly TranslateManipulator TranslateXManipulator;

        /// <summary>
        /// Y轴平移操纵器
        /// </summary>
        private readonly TranslateManipulator TranslateYManipulator;

        /// <summary>
        ///Z轴平移操纵器
        /// </summary>
        private readonly TranslateManipulator TranslateZManipulator;

        #endregion

        #region 注册属性

        #region CanRotateX

        /// <summary>
        /// 是否可绕X轴旋转属性
        /// </summary>
        public static readonly DependencyProperty CanRotateXProperty = DependencyProperty.Register(
            "CanRotateX", typeof(bool), typeof(CombinedManipulator), new UIPropertyMetadata(true, ChildrenChanged));

        /// <summary>
        /// 获取或设置是否可绕X轴旋转
        /// </summary>
        public bool CanRotateX
        {
            get { return (bool)GetValue(CanRotateXProperty); }
            set { SetValue(CanRotateXProperty, value); }
        } 
        #endregion

        #region CanRotateY

        /// <summary>
        ///是否可绕Y轴旋转属性
        /// </summary>
        public static readonly DependencyProperty CanRotateYProperty = DependencyProperty.Register(
            "CanRotateY", typeof(bool), typeof(CombinedManipulator), new UIPropertyMetadata(true, ChildrenChanged));

        /// <summary>
        /// 获取或设置是否可绕Y轴旋转
        /// </summary>
        public bool CanRotateY
        {
            get { return (bool)GetValue(CanRotateYProperty); }
            set { SetValue(CanRotateYProperty, value); }
        } 

        #endregion

        #region CanRotateZ

        /// <summary>
        /// 是否可绕Z轴旋转属性
        /// </summary>
        public static readonly DependencyProperty CanRotateZProperty = DependencyProperty.Register(
            "CanRotateZ", typeof(bool), typeof(CombinedManipulator), new UIPropertyMetadata(true, ChildrenChanged));

        /// <summary>
        /// 获取或设置是否可绕Z轴旋转
        /// </summary>
        public bool CanRotateZ
        {
            get { return (bool)GetValue(CanRotateZProperty); }
            set { SetValue(CanRotateZProperty, value); }
        } 

        #endregion

        #region CanTranslateX

        /// <summary>
        /// 是否允许X轴向平移属性
        /// </summary>
        public static readonly DependencyProperty CanTranslateXProperty = DependencyProperty.Register(
            "CanTranslateX", typeof(bool), typeof(CombinedManipulator), new UIPropertyMetadata(true, ChildrenChanged));

        /// <summary>
        /// 获取或设置是否允许X轴向平移
        /// </summary>
        public bool CanTranslateX
        {
            get { return (bool)GetValue(CanTranslateXProperty); }
            set { SetValue(CanTranslateXProperty, value); }
        } 

        #endregion

        #region CanTranslateY

        /// <summary>
        /// 是否允许Y轴向平移属性
        /// </summary>
        public static readonly DependencyProperty CanTranslateYProperty = DependencyProperty.Register(
            "CanTranslateY", typeof(bool), typeof(CombinedManipulator), new UIPropertyMetadata(true, ChildrenChanged));

        /// <summary>
        /// 获取或设置是否允许Y轴向平移
        /// </summary>
        public bool CanTranslateY
        {
            get { return (bool)GetValue(CanTranslateYProperty); }
            set { SetValue(CanTranslateYProperty, value); }
        } 

        #endregion

        #region CanTranslateZ

        /// <summary>
        /// 是否允许Z轴向平移属性
        /// </summary>
        public static readonly DependencyProperty CanTranslateZProperty = DependencyProperty.Register(
            "CanTranslateZ", typeof(bool), typeof(CombinedManipulator), new UIPropertyMetadata(true, ChildrenChanged));

        /// <summary>
        /// 获取或设置是否允许Z轴向平移
        /// </summary>
        public bool CanTranslateZ
        {
            get { return (bool)GetValue(CanTranslateZProperty); }
            set { SetValue(CanTranslateZProperty, value); }
        } 

        #endregion

        #region Diameter

        /// <summary>
        /// 直径属性
        /// </summary>
        public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register(
            "Diameter", typeof(double), typeof(CombinedManipulator), new UIPropertyMetadata(2.0, DiameterChanged));

        /// <summary>
        /// 获取或设置直径
        /// </summary>
        public double Diameter
        {
            get { return (double)GetValue(DiameterProperty); }
            set { SetValue(DiameterProperty, value); }
        } 

        #endregion

        #region TargetTransform

        /// <summary>
        /// 目标转换属性
        /// </summary>
        public static readonly DependencyProperty TargetTransformProperty =
            DependencyProperty.Register(
                "TargetTransform",
                typeof(Transform3D),
                typeof(CombinedManipulator),
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        /// <summary>
        /// 获取或设置目标转换
        /// </summary>
        public Transform3D TargetTransform
        {
            get { return (Transform3D)GetValue(TargetTransformProperty); }
            set { SetValue(TargetTransformProperty, value); }
        } 
        #endregion

        #endregion

        #region 构造、析构

        /// <summary>
        /// 默认构造
        /// </summary>
        public CombinedManipulator()
        {
            this.TranslateXManipulator = new TranslateManipulator
            {
                Direction = new Vector3D(1, 0, 0),
                Color = Colors.Red
            };
            this.TranslateYManipulator = new TranslateManipulator
            {
                Direction = new Vector3D(0, 1, 0),
                Color = Colors.Green
            };
            this.TranslateZManipulator = new TranslateManipulator
            {
                Direction = new Vector3D(0, 0, 1),
                Color = Colors.Blue
            };
            this.RotateXManipulator = new RotateManipulator { Axis = new Vector3D(1, 0, 0), Color = Colors.Red };
            this.RotateYManipulator = new RotateManipulator { Axis = new Vector3D(0, 1, 0), Color = Colors.Green };
            this.RotateZManipulator = new RotateManipulator { Axis = new Vector3D(0, 0, 1), Color = Colors.Blue };

            BindingOperations.SetBinding(this, TransformProperty, new Binding("TargetTransform") { Source = this });

            BindingOperations.SetBinding(
                this.TranslateXManipulator,
                Manipulator.TargetTransformProperty,
                new Binding("TargetTransform") { Source = this });
            BindingOperations.SetBinding(
                this.TranslateYManipulator,
                Manipulator.TargetTransformProperty,
                new Binding("TargetTransform") { Source = this });
            BindingOperations.SetBinding(
                this.TranslateZManipulator,
                Manipulator.TargetTransformProperty,
                new Binding("TargetTransform") { Source = this });
            BindingOperations.SetBinding(
                this.RotateXManipulator, RotateManipulator.DiameterProperty, new Binding("Diameter") { Source = this });
            BindingOperations.SetBinding(
                this.RotateYManipulator, RotateManipulator.DiameterProperty, new Binding("Diameter") { Source = this });
            BindingOperations.SetBinding(
                this.RotateZManipulator, RotateManipulator.DiameterProperty, new Binding("Diameter") { Source = this });
            BindingOperations.SetBinding(
                this.RotateXManipulator,
                Manipulator.TargetTransformProperty,
                new Binding("TargetTransform") { Source = this });
            BindingOperations.SetBinding(
                this.RotateYManipulator,
                Manipulator.TargetTransformProperty,
                new Binding("TargetTransform") { Source = this });
            BindingOperations.SetBinding(
                this.RotateZManipulator,
                Manipulator.TargetTransformProperty,
                new Binding("TargetTransform") { Source = this });

            this.OnChildrenChanged();
        }

        #endregion


        #region 方法

        /// <summary>
        /// 子元素改变
        /// </summary>
        protected virtual void OnChildrenChanged()
        {
            this.Children.Clear();
            if (this.CanTranslateX)
            {
                this.Children.Add(this.TranslateXManipulator);
            }

            if (this.CanTranslateY)
            {
                this.Children.Add(this.TranslateYManipulator);
            }

            if (this.CanTranslateZ)
            {
                this.Children.Add(this.TranslateZManipulator);
            }

            if (this.CanRotateX)
            {
                this.Children.Add(this.RotateXManipulator);
            }

            if (this.CanRotateY)
            {
                this.Children.Add(this.RotateYManipulator);
            }

            if (this.CanRotateZ)
            {
                this.Children.Add(this.RotateZManipulator);
            }
        }

        /// <summary>
        /// 直径改变
        /// </summary>
        protected virtual void OnDiameterChanged()
        {
        }

        private static void ChildrenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CombinedManipulator)d).OnChildrenChanged();
        }

        private static void DiameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CombinedManipulator)d).OnDiameterChanged();
        }

        #endregion
    }
}
